﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using HslCommunication.BasicFramework;
using HslCommunication.Core.Net;
using HslCommunication.LogNet;

namespace HslCommunication.WebSocket
{
	/// <summary>
	/// WebSocket协议的实现，支持创建自定义的websocket服务器，直接给其他的网页端，客户端，手机端发送数据信息，详细看api文档说明<br />
	/// The implementation of the WebSocket protocol supports the creation of custom websocket servers and sends data information directly to other web pages, clients, and mobile phones. See the API documentation for details.
	/// </summary>
	/// <example>
	/// 使用本组件库可以非常简单方便的构造属于你自己的websocket服务器，从而实现和其他的客户端进行通信，尤其是和网页进行通讯，
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\WebSocket\WebSocketServerSample.cs" region="Sample1" title="简单的实例化" />
	/// 当客户端发送数据给服务器的时候，会发一个事件，并且把当前的会话暴露出来，下面举例打印消息，并且演示一个例子，发送数据给指定的会话。
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\WebSocket\WebSocketServerSample.cs" region="Sample2" title="接触数据" />
	/// 也可以在其他地方发送数据给所有的客户端，只要调用一个方法就可以了。
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\WebSocket\WebSocketServerSample.cs" region="Sample3" title="发送数据" />
	/// 当客户端上线之后也触发了当前的事件，我们可以手动捕获到
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\WebSocket\WebSocketServerSample.cs" region="Sample4" title="捕获上线事件" />
	/// 我们再来看看一个高级的操作，实现订阅，大多数的情况，websocket被设计成了订阅发布的操作。基本本服务器可以扩展出非常复杂功能的系统，我们来看一种最简单的操作。
	/// <br />
	/// 客户端给服务器发的数据都视为主题(topic)，这样服务器就可以辨认出主题信息，并追加主题。如下这么操作。
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\WebSocket\WebSocketServerSample.cs" region="Sample5" title="订阅实现" />
	/// 然后在发布的时候，调用下面的代码。
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\WebSocket\WebSocketServerSample.cs" region="Sample6" title="发布数据" />
	/// 可以看到，我们这里只有订阅操作，如果想要实现更为复杂的操作怎么办？丰富客户端发来的数据，携带命令，数据，就可以区分了。比如json数据。具体的实现需要看各位能力了。
	/// </example>
	// Token: 0x02000025 RID: 37
	public class WebSocketServer : NetworkServerBase
	{
		/// <summary>
		/// 实例化一个默认的对象<br />
		/// Instantiate a default object
		/// </summary>
		// Token: 0x06000251 RID: 593 RVA: 0x00009240 File Offset: 0x00007440
		public WebSocketServer()
		{
			this.retainKeys = new Dictionary<string, string>();
			this.keysLock = new object();
		}

		/// <inheritdoc />
		// Token: 0x06000252 RID: 594 RVA: 0x000092B0 File Offset: 0x000074B0
		public override void ServerStart(int port)
		{
			base.ServerStart(port);
			bool flag = this.KeepAliveSendInterval.TotalMilliseconds > 0.0;
			if (flag)
			{
				this.timerHeart = new Timer(new TimerCallback(this.ThreadTimerHeartCheck), null, 2000, (int)this.KeepAliveSendInterval.TotalMilliseconds);
			}
		}

		// Token: 0x06000253 RID: 595 RVA: 0x00009310 File Offset: 0x00007510
		private void ThreadTimerHeartCheck(object obj)
		{
			WebSocketSession[] array = null;
			object obj2 = this.sessionsLock;
			lock (obj2)
			{
				array = this.wsSessions.ToArray();
			}
			bool flag2 = array != null && array.Length != 0;
			if (flag2)
			{
				for (int i = 0; i < array.Length; i++)
				{
					bool flag3 = DateTime.Now - array[i].ActiveTime > this.KeepAlivePeriod;
					if (flag3)
					{
						this.RemoveAndCloseSession(array[i], "Heart check timeout[" + SoftBasic.GetTimeSpanDescription(DateTime.Now - array[i].ActiveTime) + "]");
					}
					else
					{
						base.Send(array[i].WsSocket, WebSocketHelper.WebScoketPackData(9, false, "Heart Check"));
					}
				}
			}
		}

		/// <inheritdoc />
		// Token: 0x06000254 RID: 596 RVA: 0x00009408 File Offset: 0x00007608
		[DebuggerStepThrough]
		protected override void ThreadPoolLogin(Socket socket, IPEndPoint endPoint)
		{
			WebSocketServer.<ThreadPoolLogin>d__3 <ThreadPoolLogin>d__ = new WebSocketServer.<ThreadPoolLogin>d__3();
			<ThreadPoolLogin>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
			<ThreadPoolLogin>d__.<>4__this = this;
			<ThreadPoolLogin>d__.socket = socket;
			<ThreadPoolLogin>d__.endPoint = endPoint;
			<ThreadPoolLogin>d__.<>1__state = -1;
			<ThreadPoolLogin>d__.<>t__builder.Start<WebSocketServer.<ThreadPoolLogin>d__3>(ref <ThreadPoolLogin>d__);
		}

		// Token: 0x06000255 RID: 597 RVA: 0x00009450 File Offset: 0x00007650
		[DebuggerStepThrough]
		private void ReceiveCallback(IAsyncResult ar)
		{
			WebSocketServer.<ReceiveCallback>d__4 <ReceiveCallback>d__ = new WebSocketServer.<ReceiveCallback>d__4();
			<ReceiveCallback>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
			<ReceiveCallback>d__.<>4__this = this;
			<ReceiveCallback>d__.ar = ar;
			<ReceiveCallback>d__.<>1__state = -1;
			<ReceiveCallback>d__.<>t__builder.Start<WebSocketServer.<ReceiveCallback>d__4>(ref <ReceiveCallback>d__);
		}

		// Token: 0x06000256 RID: 598 RVA: 0x00009490 File Offset: 0x00007690
		private void HandleWebsocketConnection(Socket socket, IPEndPoint endPoint, OperateResult<byte[]> headResult)
		{
			bool flag = !headResult.IsSuccess;
			if (!flag)
			{
				string @string = Encoding.UTF8.GetString(headResult.Content);
				OperateResult operateResult = WebSocketHelper.CheckWebSocketLegality(@string);
				bool flag2 = !operateResult.IsSuccess;
				if (flag2)
				{
					if (socket != null)
					{
						socket.Close();
					}
					ILogNet logNet = base.LogNet;
					if (logNet != null)
					{
						logNet.WriteDebug(this.ToString(), string.Format("[{0}] WebScoket Check Failed:", endPoint) + operateResult.Message + Environment.NewLine + @string);
					}
				}
				else
				{
					OperateResult<byte[]> response = WebSocketHelper.GetResponse(@string);
					bool flag3 = !response.IsSuccess;
					if (flag3)
					{
						if (socket != null)
						{
							socket.Close();
						}
						ILogNet logNet2 = base.LogNet;
						if (logNet2 != null)
						{
							logNet2.WriteDebug(this.ToString(), string.Format("[{0}] GetResponse Failed:", endPoint) + response.Message);
						}
					}
					else
					{
						OperateResult operateResult2 = base.Send(socket, response.Content);
						bool flag4 = !operateResult2.IsSuccess;
						if (!flag4)
						{
							WebSocketSession webSocketSession = new WebSocketSession
							{
								ActiveTime = DateTime.Now,
								Remote = endPoint,
								WsSocket = socket,
								IsQASession = (@string.Contains("HslRequestAndAnswer: true") || @string.Contains("HslRequestAndAnswer:true"))
							};
							Match match = Regex.Match(@string, "GET [\\S\\s]+ HTTP/1", RegexOptions.IgnoreCase);
							bool success = match.Success;
							if (success)
							{
								webSocketSession.Url = match.Value.Substring(4, match.Value.Length - 11);
							}
							try
							{
								string[] webSocketSubscribes = WebSocketHelper.GetWebSocketSubscribes(@string);
								bool flag5 = webSocketSubscribes != null;
								if (flag5)
								{
									webSocketSession.Topics = new List<string>(webSocketSubscribes);
									bool flag6 = this.isRetain;
									if (flag6)
									{
										object obj = this.keysLock;
										lock (obj)
										{
											for (int i = 0; i < webSocketSession.Topics.Count; i++)
											{
												bool flag8 = this.retainKeys.ContainsKey(webSocketSession.Topics[i]);
												if (flag8)
												{
													operateResult2 = base.Send(socket, WebSocketHelper.WebScoketPackData(1, false, this.retainKeys[webSocketSession.Topics[i]]));
													bool flag9 = !operateResult2.IsSuccess;
													if (flag9)
													{
														return;
													}
												}
											}
										}
									}
								}
								socket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), webSocketSession);
								this.AddWsSession(webSocketSession);
							}
							catch (Exception ex)
							{
								if (socket != null)
								{
									socket.Close();
								}
								ILogNet logNet3 = base.LogNet;
								if (logNet3 != null)
								{
									logNet3.WriteDebug(this.ToString(), string.Format("[{0}] BeginReceive Failed: {1}", webSocketSession.Remote, ex.Message));
								}
								return;
							}
							WebSocketServer.OnClientConnectedDelegate onClientConnected = this.OnClientConnected;
							if (onClientConnected != null)
							{
								onClientConnected(webSocketSession);
							}
						}
					}
				}
			}
		}

		// Token: 0x06000257 RID: 599 RVA: 0x000097AC File Offset: 0x000079AC
		private void HandleWebsocketMessage(WebSocketSession session, OperateResult<WebSocketMessage> read)
		{
			bool flag = !read.IsSuccess;
			if (flag)
			{
				this.RemoveAndCloseSession(session, null);
			}
			else
			{
				session.ActiveTime = DateTime.Now;
				bool flag2 = read.Content.OpCode == 8;
				if (flag2)
				{
					Socket wsSocket = session.WsSocket;
					if (wsSocket != null)
					{
						wsSocket.Close();
					}
					this.RemoveAndCloseSession(session, Encoding.UTF8.GetString(read.Content.Payload));
				}
				else
				{
					bool flag3 = read.Content.OpCode == 9;
					if (flag3)
					{
						OperateResult operateResult = base.Send(session.WsSocket, WebSocketHelper.WebScoketPackData(10, false, read.Content.Payload));
						bool flag4 = !operateResult.IsSuccess;
						if (flag4)
						{
							this.RemoveAndCloseSession(session, "HandleWebsocketMessage -> 09 opCode send back exception -> " + operateResult.Message);
							return;
						}
					}
					else
					{
						bool flag5 = read.Content.OpCode == 10;
						if (flag5)
						{
							ILogNet logNet = base.LogNet;
							if (logNet != null)
							{
								logNet.WriteDebug(this.ToString(), string.Format("[{0}] {1}", session.Remote, read.Content));
							}
						}
						else
						{
							WebSocketServer.OnClientApplicationMessageReceiveDelegate onClientApplicationMessageReceive = this.OnClientApplicationMessageReceive;
							if (onClientApplicationMessageReceive != null)
							{
								onClientApplicationMessageReceive(session, read.Content);
							}
						}
					}
					try
					{
						session.WsSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), session);
					}
					catch (Exception ex)
					{
						Socket wsSocket2 = session.WsSocket;
						if (wsSocket2 != null)
						{
							wsSocket2.Close();
						}
						this.RemoveAndCloseSession(session, "BeginReceive Exception -> " + ex.Message);
					}
				}
			}
		}

		/// <summary>
		/// websocket的消息收到时触发<br />
		/// Triggered when a websocket message is received
		///             </summary>
		// Token: 0x14000004 RID: 4
		// (add) Token: 0x06000258 RID: 600 RVA: 0x00009954 File Offset: 0x00007B54
		// (remove) Token: 0x06000259 RID: 601 RVA: 0x0000998C File Offset: 0x00007B8C
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event WebSocketServer.OnClientApplicationMessageReceiveDelegate OnClientApplicationMessageReceive;

		/// <summary>
		/// Websocket的客户端连接上来时触发<br />
		/// Triggered when a Websocket client connects
		/// </summary>
		// Token: 0x14000005 RID: 5
		// (add) Token: 0x0600025A RID: 602 RVA: 0x000099C4 File Offset: 0x00007BC4
		// (remove) Token: 0x0600025B RID: 603 RVA: 0x000099FC File Offset: 0x00007BFC
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event WebSocketServer.OnClientConnectedDelegate OnClientConnected;

		/// <summary>
		/// Websocket的客户端下线时触发<br />
		/// Triggered when Websocket client connects
		/// </summary>
		// Token: 0x14000006 RID: 6
		// (add) Token: 0x0600025C RID: 604 RVA: 0x00009A34 File Offset: 0x00007C34
		// (remove) Token: 0x0600025D RID: 605 RVA: 0x00009A6C File Offset: 0x00007C6C
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event WebSocketServer.OnClientConnectedDelegate OnClientDisConnected;

		/// <inheritdoc />
		// Token: 0x0600025E RID: 606 RVA: 0x00009AA1 File Offset: 0x00007CA1
		protected override void StartInitialization()
		{
		}

		/// <inheritdoc />
		// Token: 0x0600025F RID: 607 RVA: 0x00009AA4 File Offset: 0x00007CA4
		protected override void CloseAction()
		{
			base.CloseAction();
			this.CleanWsSession();
		}

		/// <summary>
		/// 向所有的客户端强制发送消息<br />
		/// Force message to all clients
		/// </summary>
		/// <param name="payload">消息内容</param>
		// Token: 0x06000260 RID: 608 RVA: 0x00009AB8 File Offset: 0x00007CB8
		public void PublishAllClientPayload(string payload)
		{
			object obj = this.sessionsLock;
			lock (obj)
			{
				for (int i = 0; i < this.wsSessions.Count; i++)
				{
					bool isQASession = this.wsSessions[i].IsQASession;
					if (!isQASession)
					{
						OperateResult operateResult = base.Send(this.wsSessions[i].WsSocket, WebSocketHelper.WebScoketPackData(1, false, payload));
						bool flag2 = !operateResult.IsSuccess;
						if (flag2)
						{
							ILogNet logNet = base.LogNet;
							if (logNet != null)
							{
								logNet.WriteError(this.ToString(), string.Format("[{0}] Send Failed: {1}", this.wsSessions[i].Remote, operateResult.Message));
							}
						}
					}
				}
			}
		}

		/// <summary>
		/// 向订阅了topic主题的客户端发送消息<br />
		/// Send messages to clients subscribed to topic
		/// </summary>
		/// <param name="topic">主题</param>
		/// <param name="payload">消息内容</param>
		// Token: 0x06000261 RID: 609 RVA: 0x00009B9C File Offset: 0x00007D9C
		public void PublishClientPayload(string topic, string payload)
		{
			object obj = this.sessionsLock;
			lock (obj)
			{
				for (int i = 0; i < this.wsSessions.Count; i++)
				{
					bool isQASession = this.wsSessions[i].IsQASession;
					if (!isQASession)
					{
						bool flag2 = this.wsSessions[i].IsClientSubscribe(topic);
						if (flag2)
						{
							OperateResult operateResult = base.Send(this.wsSessions[i].WsSocket, WebSocketHelper.WebScoketPackData(1, false, payload));
							bool flag3 = !operateResult.IsSuccess;
							if (flag3)
							{
								ILogNet logNet = base.LogNet;
								if (logNet != null)
								{
									logNet.WriteError(this.ToString(), string.Format("[{0}] Send Failed: {1}", this.wsSessions[i].Remote, operateResult.Message));
								}
							}
						}
					}
				}
			}
			bool flag4 = this.isRetain;
			if (flag4)
			{
				this.AddTopicRetain(topic, payload);
			}
		}

		/// <summary>
		/// 向指定的客户端发送数据<br />
		/// Send data to the specified client
		/// </summary>
		/// <param name="session">会话内容</param>
		/// <param name="payload">消息内容</param>
		// Token: 0x06000262 RID: 610 RVA: 0x00009CB4 File Offset: 0x00007EB4
		public void SendClientPayload(WebSocketSession session, string payload)
		{
			base.Send(session.WsSocket, WebSocketHelper.WebScoketPackData(1, false, payload));
		}

		/// <summary>
		/// 给一个当前的会话信息动态添加订阅的主题<br />
		/// Dynamically add subscribed topics to a current session message
		/// </summary>
		/// <param name="session">会话内容</param>
		/// <param name="topic">主题信息</param>
		// Token: 0x06000263 RID: 611 RVA: 0x00009CCB File Offset: 0x00007ECB
		public void AddSessionTopic(WebSocketSession session, string topic)
		{
			session.AddTopic(topic);
			this.PublishSessionTopic(session, topic);
		}

		/// <summary>
		/// 获取当前的在线的客户端数量<br />
		/// Get the current number of online clients
		/// </summary>
		// Token: 0x17000087 RID: 135
		// (get) Token: 0x06000264 RID: 612 RVA: 0x00009CDF File Offset: 0x00007EDF
		public int OnlineCount
		{
			get
			{
				return this.wsSessions.Count;
			}
		}

		/// <summary>
		/// 获取或设置当前的服务器是否对订阅主题信息缓存，方便订阅客户端立即收到结果，默认开启<br />
		/// Gets or sets whether the current server caches the topic information of the subscription, so that the subscription client can receive the results immediately. It is enabled by default.
		/// </summary>
		// Token: 0x17000088 RID: 136
		// (get) Token: 0x06000265 RID: 613 RVA: 0x00009CEC File Offset: 0x00007EEC
		// (set) Token: 0x06000266 RID: 614 RVA: 0x00009CF4 File Offset: 0x00007EF4
		public bool IsTopicRetain
		{
			get
			{
				return this.isRetain;
			}
			set
			{
				this.isRetain = value;
			}
		}

		/// <summary>
		/// 获取当前的在线的客户端信息，可以用于额外的分析或是显示。
		/// </summary>
		// Token: 0x17000089 RID: 137
		// (get) Token: 0x06000267 RID: 615 RVA: 0x00009D00 File Offset: 0x00007F00
		public WebSocketSession[] OnlineSessions
		{
			get
			{
				WebSocketSession[] result = null;
				object obj = this.sessionsLock;
				lock (obj)
				{
					result = this.wsSessions.ToArray();
				}
				return result;
			}
		}

		/// <summary>
		/// 设置的参数，最小单位为1s，当超过设置的时间间隔必须回复PONG报文，否则服务器认定为掉线。默认120秒<br />
		/// Set the minimum unit of the parameter is 1s. When the set time interval is exceeded, the PONG packet must be returned, otherwise the server considers it to be offline. 120 seconds by default
		/// </summary>
		/// <remarks>
		/// 保持连接（Keep Alive）是一个以秒为单位的时间间隔，它是指客户端返回一个PONG报文到下一次返回PONG报文的时候，
		/// 两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。
		/// </remarks>
		// Token: 0x1700008A RID: 138
		// (get) Token: 0x06000268 RID: 616 RVA: 0x00009D50 File Offset: 0x00007F50
		// (set) Token: 0x06000269 RID: 617 RVA: 0x00009D58 File Offset: 0x00007F58
		public TimeSpan KeepAlivePeriod { get; set; } = TimeSpan.FromSeconds(120.0);

		/// <summary>
		/// 获取或是设置用于保持连接的心跳时间的发送间隔。默认30秒钟，需要在服务启动之前设置<br />
		/// Gets or sets the sending interval of the heartbeat time used to keep the connection. 30 seconds by default, need to be set before the service starts
		/// </summary>
		// Token: 0x1700008B RID: 139
		// (get) Token: 0x0600026A RID: 618 RVA: 0x00009D61 File Offset: 0x00007F61
		// (set) Token: 0x0600026B RID: 619 RVA: 0x00009D69 File Offset: 0x00007F69
		public TimeSpan KeepAliveSendInterval { get; set; } = TimeSpan.FromSeconds(30.0);

		// Token: 0x0600026C RID: 620 RVA: 0x00009D74 File Offset: 0x00007F74
		private void CleanWsSession()
		{
			object obj = this.sessionsLock;
			lock (obj)
			{
				for (int i = 0; i < this.wsSessions.Count; i++)
				{
					Socket wsSocket = this.wsSessions[i].WsSocket;
					if (wsSocket != null)
					{
						wsSocket.Close();
					}
				}
				this.wsSessions.Clear();
			}
		}

		// Token: 0x0600026D RID: 621 RVA: 0x00009DF8 File Offset: 0x00007FF8
		private void AddWsSession(WebSocketSession session)
		{
			object obj = this.sessionsLock;
			lock (obj)
			{
				this.wsSessions.Add(session);
			}
			ILogNet logNet = base.LogNet;
			if (logNet != null)
			{
				logNet.WriteDebug(this.ToString(), string.Format("Client[{0}] Online", session.Remote));
			}
		}

		/// <summary>
		/// 让Websocket客户端正常下线，调用本方法即可自由控制会话客户端强制下线操作。<br />
		/// Let the Websocket client go offline normally. Call this method to freely control the session client to force offline operation.
		/// </summary>
		/// <param name="session">当前的会话信息</param>
		/// <param name="reason">下线的原因，默认为空</param>
		// Token: 0x0600026E RID: 622 RVA: 0x00009E6C File Offset: 0x0000806C
		public void RemoveAndCloseSession(WebSocketSession session, string reason = null)
		{
			object obj = this.sessionsLock;
			lock (obj)
			{
				this.wsSessions.Remove(session);
			}
			Socket wsSocket = session.WsSocket;
			if (wsSocket != null)
			{
				wsSocket.Close();
			}
			ILogNet logNet = base.LogNet;
			if (logNet != null)
			{
				logNet.WriteDebug(this.ToString(), string.Format("Client[{0}]  Offline {1}", session.Remote, reason));
			}
			WebSocketServer.OnClientConnectedDelegate onClientDisConnected = this.OnClientDisConnected;
			if (onClientDisConnected != null)
			{
				onClientDisConnected(session);
			}
		}

		// Token: 0x0600026F RID: 623 RVA: 0x00009F08 File Offset: 0x00008108
		private void AddTopicRetain(string topic, string payload)
		{
			object obj = this.keysLock;
			lock (obj)
			{
				bool flag2 = this.retainKeys.ContainsKey(topic);
				if (flag2)
				{
					this.retainKeys[topic] = payload;
				}
				else
				{
					this.retainKeys.Add(topic, payload);
				}
			}
		}

		// Token: 0x06000270 RID: 624 RVA: 0x00009F78 File Offset: 0x00008178
		private void PublishSessionTopic(WebSocketSession session, string topic)
		{
			bool flag = false;
			string message = string.Empty;
			object obj = this.keysLock;
			lock (obj)
			{
				bool flag3 = this.retainKeys.ContainsKey(topic);
				if (flag3)
				{
					flag = true;
					message = this.retainKeys[topic];
				}
			}
			bool flag4 = flag;
			if (flag4)
			{
				base.Send(session.WsSocket, WebSocketHelper.WebScoketPackData(1, false, message));
			}
		}

		/// <inheritdoc />
		// Token: 0x06000271 RID: 625 RVA: 0x0000A000 File Offset: 0x00008200
		public override string ToString()
		{
			return string.Format("WebSocketServer[{0}]", base.Port);
		}

		// Token: 0x040000C2 RID: 194
		private readonly Dictionary<string, string> retainKeys;

		// Token: 0x040000C3 RID: 195
		private readonly object keysLock;

		// Token: 0x040000C4 RID: 196
		private bool isRetain = true;

		// Token: 0x040000C5 RID: 197
		private readonly List<WebSocketSession> wsSessions = new List<WebSocketSession>();

		// Token: 0x040000C6 RID: 198
		private readonly object sessionsLock = new object();

		// Token: 0x040000C7 RID: 199
		private Timer timerHeart;

		/// <summary>
		/// websocket的消息收到委托<br />
		/// websocket message received delegate
		/// </summary>
		/// <param name="session">当前的会话对象</param>
		/// <param name="message">websocket的消息</param>
		// Token: 0x020001B6 RID: 438
		// (Invoke) Token: 0x0600218A RID: 8586
		public delegate void OnClientApplicationMessageReceiveDelegate(WebSocketSession session, WebSocketMessage message);

		/// <summary>
		/// 当前websocket连接上服务器的事件委托<br />
		/// Event delegation of the server on the current websocket connection
		/// </summary>
		/// <param name="session">当前的会话对象</param>
		// Token: 0x020001B7 RID: 439
		// (Invoke) Token: 0x0600218E RID: 8590
		public delegate void OnClientConnectedDelegate(WebSocketSession session);
	}
}
